package com.delta.rafg.core.log.impl;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Properties;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueSender;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.delta.rafg.core.log.ILogQueuer;
import com.delta.rafg.core.log.LogData;
import com.delta.rafg.coredata.AObject;

public class LogQueuerJMS extends AObject implements ILogQueuer {

    private static final long serialVersionUID = 474835396968719424L;

    @Override
    public void queueToLog(LogData pLogData) {
        try {

            open();

            queueConnection.start();
            queueSession = queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);

            ObjectMessage message = queueSession.createObjectMessage();
            message.setObject(pLogData);

            // this is one way
            MessageProducer msgProducer = queueSession.createProducer(queue);
            msgProducer.send(message);

            // this is another way to accomplish this
            // queueSender = queueSession.createSender(queue);
            // queueSender.send(message);
            // queueSender.send(queueSession.createMessage());

        }
        catch ( JMSException e ) {
            e.printStackTrace();
            System.out.println("pLogData" + pLogData);
        }
        catch ( Throwable e ) {
            e.printStackTrace();
            System.out.println("pLogData" + pLogData);
        }
        finally {
            try {
                close();
            }
            catch ( JMSException e ) {
                e.printStackTrace();
            }
        }

    }

    /**
     * Initializes the Context and looks up Log Writer.
     */
    private static void initialize() {
        if ( initialized )
            return;
        try {
            queueName = loggerproperties.getProperty("QUEUE_NAME");
            jndiContext = getInitialContext(loggerproperties.getProperty("URL"));
            queueConnectionFactory = (ConnectionFactory) doRemoteLookup(loggerproperties.getProperty("URL"),
                    loggerproperties.getProperty("QUEUE_CONN_FACTORY"));
            queue = (Queue) jndiContext.lookup(queueName);
        }
        catch ( NamingException e ) {
            e.printStackTrace();
        }
        initialized = true;
    }

    /**
     * Opens the connection to Log Writer.
     * 
     * @throws JMSException
     */
    private static void open() throws JMSException {
        if ( queueConnection == null ) {
            queueConnection = queueConnectionFactory.createConnection();
        }
    }

    /**
     * Closes the connection to Log Writer.
     * 
     * @throws JMSException
     */
    private static void close() throws JMSException {
        if ( queueConnection != null ) {
            // queueConnection.stop();
            queueConnection.close();
            queueConnection = null;
        }
    }

    /**
     * Creates an initial context and returns it. also caches it for future use.
     * 
     * @param pUrl
     * @return
     * @throws NamingException
     */
    private static InitialContext getInitialContext(String pUrl) throws NamingException {
        InitialContext ic = contextMap.get(pUrl);
        if ( ic == null ) {
            if ( MYURL.equalsIgnoreCase(pUrl) ) {
                ic = new InitialContext();
            }
            else {
                Properties properties = new Properties();
                properties.put(InitialContext.PROVIDER_URL, pUrl);
                ic = new InitialContext(properties);
            }
            contextMap.put(pUrl, ic);
        }
        return ic;
    }

    /**
     * @param pUrl
     * @param pName
     * @return
     * @throws NamingException
     */
    private static Object doRemoteLookup(String pUrl, String pName) throws NamingException {
        return getInitialContext(pUrl).lookup(pName);
    }

    // contextMap holds the initial contexts so you don't have to keep creating them
    private static HashMap<String, InitialContext> contextMap = new HashMap<String, InitialContext>();

    /**
     * Determines where we are.
     */
    public static void determineContext() {
        MYURL = "whq1cmsrxp00028:9080";
        // this should be read from configuration
    }

    static String             queueName              = null;
    static ConnectionFactory  queueConnectionFactory = null;
    static Context            jndiContext            = null;
    static Connection         queueConnection        = null;
    static Session            queueSession           = null;
    static Queue              queue                  = null;
    static QueueSender        queueSender            = null;

    private static boolean    initialized            = false;

    private static Properties loggerproperties       = null;
    static {
        loggerproperties = new Properties();
        try {
            loggerproperties.loadFromXML(new FileInputStream("loggerproperties.xml"));
        }
        catch ( Exception e ) {
            loggerproperties.put("CONNECTION_TYPE", "JMS");
            loggerproperties.put("URL", "whq1cmsrxp00028:9080");
            loggerproperties.put("QUEUE_CONN_FACTORY", "jms/RAFGQCF");
            loggerproperties.put("QUEUE_NAME", "jms/RAFGLogWriterQueue");
            e.printStackTrace();

            try {
                loggerproperties.storeToXML(new FileOutputStream("loggerproperties.xml"),
                        "RAFG properties required to reach log writer");
            }
            catch ( FileNotFoundException e1 ) {
                e.printStackTrace();
            }
            catch ( IOException e1 ) {
                e.printStackTrace();
            }
        }
    }

    private static String     MYURL                  = "";
    static {
        determineContext();
    }

    static {
        initialize();
    }

}
